package com.sun.common;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.util.ListUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.sun.dto.DrugDto;
import com.sun.dto.ExcelStateDataVo;
import com.sun.entity.Category;
import com.sun.entity.Drug;
import com.sun.entity.DrugSupplier;
import com.sun.entity.Supplier;
import com.sun.service.CategoryService;
import com.sun.service.DrugService;
import com.sun.service.DrugSupplierService;
import com.sun.service.SupplierService;
import com.sun.utils.JsonUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @Project: hospitalDrugInformationManagement
 * @Author: 86178
 * @Date: 2023/2/23 15:15
 * @FileName: ExcelListener
 * @Description: ""
 */
@Slf4j
public class ExcelListener extends AnalysisEventListener<DrugDto> {

    /**
     * 每隔5条存储数据库，实际使用中可以100条，然后清理list ，方便内存回收
     */
    private static final int BATCH_COUNT = 100;
    List<String> errList = new ArrayList<>();
    private DrugService drugService;
    private CategoryService categoryService;
    private SupplierService supplierService;
    private ExcelStateDataVo excelStateDataVo;
    private DrugSupplierService drugSupplierService;
    /**
     * 缓存的数据
     */
    private List<Drug> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
    private List<DrugSupplier> cachedDataList1 = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
    private int currentRow = 0;
    private boolean flag = true;


    /**
     * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
     */
    public ExcelListener(DrugService drugService, CategoryService categoryService, SupplierService supplierService, ExcelStateDataVo excelStateDataVo, DrugSupplierService drugSupplierService) {
        this.drugService = drugService;
        this.categoryService = categoryService;
        this.supplierService = supplierService;
        this.excelStateDataVo = excelStateDataVo;
        this.drugSupplierService = drugSupplierService;
    }


    /**
     * 读取表头中的内容
     * @param headMap
     * @param context
     */
    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        System.out.println("表头的内容为"+headMap);
    }

    /**
     * 这个每一条数据解析都会来调用
     *
     * @param data
     * @param context
     */
    @SneakyThrows
    @Override
    public void invoke(DrugDto data, AnalysisContext context) {
        currentRow++;
        flag = false;
        System.out.println("解析到一条数据:" + JsonUtils.getBeanToJson(data));
        if (data != null) {

            //这里查数据库替换相应的字段
            Category category = categoryService.selectByName(data.getCategoryName());
            Supplier supplier = supplierService.selectByName(data.getSupplierName());
            if (category == null) {
                Category category1 = new Category();
                category1.setCategoryId(IdWorker.getId());
                category1.setName(data.getCategoryName());
                categoryService.save(category1);
                data.setCategoryId(category1.getCategoryId());
            } else {
                data.setCategoryId(category.getCategoryId());
            }
            if (supplier == null) {
                Supplier supplier1 = new Supplier();
                supplier1.setSupplierId(IdWorker.getId());
                supplier1.setSupplierName(data.getSupplierName());
                supplierService.save(supplier1);
                data.setSupplierId(supplier1.getSupplierId());
            } else {
                data.setSupplierId(supplier.getSupplierId());
            }

            //查询药品和厂商的数据库
            LambdaQueryWrapper<DrugSupplier> lambdaQueryWrapper2 = new LambdaQueryWrapper<>();
            lambdaQueryWrapper2.eq(DrugSupplier::getDrugName, data.getDrugName()).eq(DrugSupplier::getSupplierId, data.getSupplierId());
            DrugSupplier drugSupplier = drugSupplierService.getOne(lambdaQueryWrapper2);
            if (drugSupplier != null) {
                errList.add(String.format("第%s行%s有重复，数据库中已有该厂商的药品信息", currentRow, data.getDrugName()));
                return;
            }
            LambdaQueryWrapper<Drug> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(Drug::getDrugName, data.getDrugName());
            Drug drug = drugService.getOne(lambdaQueryWrapper);
            if (drug == null) {
                data.setStatus(1);
                cachedDataList.add(data);
            }
            DrugSupplier drugSupplier1 = new DrugSupplier();
            drugSupplier1.setPrice(data.getPrice());
            drugSupplier1.setDrugName(data.getDrugName());
            drugSupplier1.setSupplierId(data.getSupplierId());
            drugSupplier1.setSupplierName(data.getSupplierName());
            cachedDataList1.add(drugSupplier1);

            if (cachedDataList.size() >= BATCH_COUNT) {
                drugService.saveBatch(cachedDataList);
                // 存储完成清理 list
                cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
            }
            if (cachedDataList1.size() >= BATCH_COUNT) {
                drugSupplierService.saveBatch(cachedDataList1);
                // 存储完成清理 list
                cachedDataList1 = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
            }
        }

    }

    /**
     * 所有数据解析完成了 都会来调用
     *
     * @param context
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        //插入数据库
        drugService.saveBatch(cachedDataList);
        drugSupplierService.saveBatch(cachedDataList1);
        log.info(JsonUtils.getBeanToJson(cachedDataList));
        if (!errList.isEmpty()) {
            excelStateDataVo.setErrList(errList);
        }
        excelStateDataVo.setSuccessCount(currentRow - errList.size());
        excelStateDataVo.setNullFile(flag);
    }

    /**
     * 监听器实现这个方法就可以在读取数据的时候获取到异常信息
     */
    @Override
    public void onException(Exception exception, AnalysisContext context) {
        log.error("解析失败，但是继续解析下一行:{}", exception.getMessage());
        errList.add(String.format("解析失败，但是继续解析下一行:%s", exception.getMessage()));
        // 如果是某一个单元格的转换异常 能获取到具体行号
        // 如果要获取头的信息 配合invokeHeadMap使用
        if (exception instanceof ExcelDataConvertException) {
            ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException) exception;
            log.error("第{}行，第{}列解析异常", excelDataConvertException.getRowIndex(),
                    excelDataConvertException.getColumnIndex());
            errList.add(String.format("第%s行，第%s列解析异常", excelDataConvertException.getRowIndex(),
                    excelDataConvertException.getColumnIndex()));
        }
    }

}
